#include "pch.h"
#include "Scheduler.h"

#include <services/provider.hpp>




Scheduler::Scheduler(services::provider::const_ptr provider)
	: m_scheduler(provider->service<services::scheduler>())
	, m_logger(provider->service<logger::stream>())
	, m_maxExceptions(5)
{}
///////////////////////////////////////////////////////////////////////////////////////////////////

Scheduler::~Scheduler()
{
	// When we're destroyed, we remove all DataProcessor tasks from
	// the scheduler...
	stop();
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Scheduler::add(DataProcessor::Ptr processor)
{
	verify(processor != DataProcessor::Ptr());

	auto task = services::task::ptr(new services::task(boost::bind(&Scheduler::run_processor, this, processor)));
	m_scheduler->add(task);
	m_tasks << TaskProc(task, processor);
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Scheduler::stop()
{
	std::for_each(m_tasks.begin(), m_tasks.end(), [&](TaskProc& task)
	{
		m_scheduler->remove(task.first);
	});
}
///////////////////////////////////////////////////////////////////////////////////////////////////




void Scheduler::run_processor(DataProcessor::Ptr processor)
{
	try
	{
		if(processor->enabled())
		{
			// Wake-up the processor, if the specified time has been reached
			if(processor->sleep())
				if(*processor->wakeUp() >= boost::posix_time::microsec_clock::local_time())
					processor->unpause();

			if(!processor->sleep())
				processor->process();
		}
	}
	catch(boostext::critical_exception&)
	{
		// A critical exception disables the processor right-away
		processor->addException();
		processor->disable();
	}
	catch(boost::exception&)
	{
		processor->addException();
	}
	catch(std::exception&)
	{
		processor->addException();
	}
	catch(...)
	{
		// An unknown exception disables the processor
		processor->addException();
		processor->disable();
	}

	// Too much exceptions cause the processor to be disabled
	if(processor->numExceptions() > m_maxExceptions)
		// TODO: Log this
		processor->disable();
}
///////////////////////////////////////////////////////////////////////////////////////////////////
